#include "RenderTexture.h"

namespace egg{

    RenderTexture::RenderTexture(uint32 _w,uint32 _h):
    RenderTarget(_w,_h){
        glGenFramebuffers(1, &mID);
        GraphicDevice_CatchError;
    }

    RenderTexture::~RenderTexture(){
        glDeleteFramebuffers(1,&mID);
        GraphicDevice_CatchError;
    }

    void RenderTexture::reserve(uint32 _w,uint32 _h){
        if(mWidth>=_w&&mHeight>=_h)
            return;
        mWidth=_w;
        mHeight=_h;
        for(int i=0;i<mColors.size();i++){
            mColors[i]->resize(_w,_h);
        }
        if(mDepthBuffer!=0){
            mDepthBuffer->resize(_w,_h);
        }
        if(mDepthTexture!=0)
            mDepthTexture->resize(_w,_h);
    }

    void RenderTexture::attachColor(uint32 _slot,Texture2DPtr _color){
        gDevice->setRenderTarget(mID);
        glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            _slot+GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            _color->getID(),
            0);
        GraphicDevice_CatchError;
        uint32 slots[8];//8 is enough
        mColors.insert(make_pair(_slot,_color));
        map<uint32,Texture2DPtr>::iterator itr=mColors.begin();
        for(uint32 i=0;itr!=mColors.end();i++,itr++){
            slots[i]=itr->first+GL_COLOR_ATTACHMENT0;
        }
        glDrawBuffers(mColors.size(),&slots[0]);
        GraphicDevice_CatchError;
        gDevice->setRenderTarget(0);
    }

    void RenderTexture::attachDepth(Texture2DPtr _depth){
        if(mDepthBuffer!=0)
            mDepthBuffer=0;
        mDepthTexture=_depth;
        gDevice->setRenderTarget(mID);
        glBindTexture(GL_TEXTURE_2D,_depth->getID());
        glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            GL_DEPTH_ATTACHMENT,
            GL_TEXTURE_2D,
            _depth->getID(),
            0);
        GraphicDevice_CatchError;
        if(_depth->getPixelFormat()==PF_Depth24Stencil8){
            glFramebufferTexture2D(
                GL_FRAMEBUFFER,
                GL_STENCIL_ATTACHMENT,
                GL_TEXTURE_2D,
                _depth->getID(),
                0);
            GraphicDevice_CatchError;
        }
        GLenum check=glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if(check!=GL_FRAMEBUFFER_COMPLETE){
            LogMgr->logMessage("framebuffer error");
        }
        gDevice->setRenderTarget(0);
        glBindTexture(GL_TEXTURE_2D,0);
    }

    void RenderTexture::attachDepth(DepthBufferPtr _depth){
        if(mDepthTexture!=0)
            mDepthTexture=0;
        mDepthBuffer=_depth;
        gDevice->setRenderTarget(mID);
        glFramebufferRenderbuffer(
            GL_FRAMEBUFFER,
            GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,
            _depth->getID());
        GraphicDevice_CatchError;
        if(_depth->hasStencil()){
            glFramebufferRenderbuffer(
                GL_FRAMEBUFFER,
                GL_STENCIL_ATTACHMENT,
                GL_RENDERBUFFER,_depth->getID());
            GraphicDevice_CatchError;
        }
        gDevice->setRenderTarget(0);
    }

    void RenderTexture::blitTo(RenderTexturePtr& _dest,bool _depth){
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER,_dest->getID());
        glBindFramebuffer(GL_READ_FRAMEBUFFER,mID);
        glBlitFramebuffer(
            0,0,mWidth,mHeight,
            0,0,mWidth,mHeight,
            GL_COLOR_BUFFER_BIT,GL_LINEAR);
        glBindFramebuffer(GL_READ_FRAMEBUFFER,0);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);
        GraphicDevice_CatchError;
    }

}